home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Graphics / Plotting / aa_Intel_Only / Gnuplot / GnuplotSource / graphics.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-12  |  53.9 KB  |  2,028 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: graphics.c%v 3.38.2.119 1993/04/26 00:02:13 woo Exp woo $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - graphics.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *  
  20.  * This software is provided "as is" without express or implied warranty.
  21.  * 
  22.  *
  23.  * AUTHORS
  24.  * 
  25.  *   Original Software:
  26.  *     Thomas Williams,  Colin Kelley.
  27.  * 
  28.  *   Gnuplot 2.0 additions:
  29.  *       Russell Lang, Dave Kotz, John Campbell.
  30.  *
  31.  *   Gnuplot 3.0 additions:
  32.  *       Gershon Elber and many others.
  33.  *
  34.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  35.  * Added user-specified bases for log scaling.
  36.  * 
  37.  * Send your comments or suggestions to 
  38.  *  info-gnuplot@dartmouth.edu.
  39.  * This is a mailing list; to join it send a note to 
  40.  *  info-gnuplot-request@dartmouth.edu.  
  41.  * Send bug reports to
  42.  *  bug-gnuplot@dartmouth.edu.
  43.  */
  44.  
  45. #include <stdio.h>
  46. #include <math.h>
  47. #include <assert.h>
  48. #if !defined(u3b2)
  49. #include <time.h>
  50. #endif
  51. #include "plot.h"
  52. #include "setshow.h"
  53.  
  54. #ifdef DJGPP
  55. #define time_t unsigned long
  56. #endif
  57.  
  58. #ifndef AMIGA_SC_6_1
  59. extern char *strcpy(),*strncpy(),*strcat(),*ctime();
  60. #endif /* !AMIGA_SC_6_1 */
  61. char *tdate;
  62. #ifdef AMIGA_AC_5
  63. time_t dated;
  64. #else
  65. #if defined(apollo) || defined(sequent) || defined(u3b2)
  66. #include <sys/types.h> /* typedef long time_t; */
  67. #endif
  68. time_t dated; /* ,time(); */
  69. #include <time.h>
  70. #endif
  71.  
  72. void plot_impulses();
  73. void plot_lines();
  74. void plot_points();
  75. void plot_dots();
  76. void plot_bars();
  77. void plot_boxes();
  78. void edge_intersect();
  79. TBOOLEAN two_edge_intersect();
  80.  
  81. void plot_steps();            /* JG */
  82. void edge_intersect_steps();         /* JG */
  83. TBOOLEAN two_edge_intersect_steps();    /* JG */
  84.  
  85. /* for plotting error bars */
  86. #define ERRORBARTIC (t->h_tic/2) /* half the width of error bar tic mark */
  87.  
  88. #ifndef max        /* Lattice C has max() in math.h, but shouldn't! */
  89. #define max(a,b) ((a > b) ? a : b)
  90. #endif
  91.  
  92. #ifndef min
  93. #define min(a,b) ((a < b) ? a : b)
  94. #endif
  95.  
  96. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  97.  
  98. /* True if a and b have the same sign or zero (positive or negative) */
  99. #define samesign(a,b) ((a) * (b) >= 0)
  100.  
  101. /* Define the boundary of the plot
  102.  * These are computed at each call to do_plot, and are constant over
  103.  * the period of one do_plot. They actually only change when the term
  104.  * type changes and when the 'set size' factors change. 
  105.  */
  106. static int xleft, xright, ybot, ytop;
  107.  
  108. /* Boundary and scale factors, in user coordinates */
  109. /* x_min, x_max, y_min, y_max are local to this file and
  110.  * are not the same as variables of the same names in other files
  111.  */
  112. static double x_min, x_max, y_min, y_max;
  113. static double xscale, yscale;
  114.  
  115. /* And the functions to map from user to terminal coordinates */
  116. #define map_x(x) (int)(xleft+(x-x_min)*xscale+0.5) /* maps floating point x to screen */ 
  117. #define map_y(y) (int)(ybot+(y-y_min)*yscale+0.5)    /* same for y */
  118.  
  119. /* (DFK) Watch for cancellation error near zero on axes labels */
  120. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  121. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  122. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  123.  
  124. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  125.  * macro, so I write it as a function on that machine.
  126.  */
  127. #ifndef sun386
  128. /* (DFK) Use 10^x if logscale is in effect, else x */
  129. #define CheckLog(is_log, base_log, x) ((is_log) ? pow(base_log, (x)) : (x))
  130. #else
  131. static double
  132. CheckLog(log, base_log, x)
  133.      TBOOLEAN is_log;
  134.      double base_log;
  135.      double x;
  136. {
  137.   if (is_log)
  138.     return(pow(base_log, x));
  139.   else
  140.     return(x);
  141. }
  142. #endif /* sun386 */
  143.  
  144. double
  145. LogScale(coord, is_log, log_base_log, what, axis)
  146.     double coord;            /* the value */
  147.     TBOOLEAN is_log;            /* is this axis in logscale? */
  148.         double log_base_log;        /* if so, the log of its base */
  149.     char *what;            /* what is the coord for? */
  150.     char *axis;            /* which axis is this for ("x" or "y")? */
  151. {
  152.     if (is_log) {
  153.        if (coord <= 0.0) {
  154.           char errbuf[100];        /* place to write error message */
  155.         (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  156.                 what, axis, coord);
  157.           (*term_tbl[term].text)();
  158.           (void) fflush(outfile);
  159.           int_error(errbuf, NO_CARET);
  160.        } else
  161.         return(log(coord)/log_base_log);
  162.     }
  163.     return(coord);
  164. }
  165.  
  166. /* borders of plotting area */
  167. /* computed once on every call to do_plot */
  168. boundary(scaling)
  169.     TBOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  170. {
  171.     register struct termentry *t = &term_tbl[term];
  172.     /* luecken@udel.edu modifications 
  173.        sizes the plot according to the presence of labels, title,... */
  174.     if (strlen(ylabel) == 0)
  175.         xleft = (t->h_char)*8;
  176.     else
  177.         xleft = (t->h_char)*10;
  178.     xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  179.     if (strlen(xlabel) == 0)
  180.         ybot = (t->v_char)*3/2 + 1;
  181.     else
  182.         if ((*t->text_angle)(1))
  183.             ybot = (t->v_char)*5/2 + 1;
  184.         else
  185.             ybot = (t->v_char)*7/2 + 1;    /* allow space for time at bottom */
  186.     if ( (strlen(title) != 0) || timedate ||
  187.       ((strlen(ylabel) != 0) && ((*t->text_angle)(1) == FALSE)) )
  188.         ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*3/2 - 1;
  189.     else
  190.         ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)/2 - 1;
  191.     (void)(*t->text_angle)(0);
  192. }
  193.  
  194.  
  195. double dbl_raise(x,y)
  196. double x;
  197. int y;
  198. {
  199. register int i;
  200. double val;
  201.  
  202.     val = 1.0;
  203.     for (i=0; i < abs(y); i++)
  204.         val *= x;
  205.     if (y < 0 ) return (1.0/val);
  206.     return(val);
  207. }
  208.  
  209.  
  210. double make_tics(tmin,tmax,logscale,base_log)
  211. double tmin,tmax;
  212. TBOOLEAN logscale;
  213. double base_log;
  214. {
  215. register double xr,xnorm,tics,tic,l10;
  216.  
  217.     xr = fabs(tmin-tmax);
  218.     
  219.     l10 = log10(xr);
  220.     if (logscale) {
  221.         tic = dbl_raise(base_log,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  222.         if (tic < 1.0)
  223.             tic = 1.0;
  224.     } else {
  225.         xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
  226.         if (xnorm <= 2)
  227.             tics = 0.2;
  228.         else if (xnorm <= 5)
  229.             tics = 0.5;
  230.         else tics = 1.0;    
  231.         tic = tics * dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  232.     }
  233.     return(tic);
  234. }
  235.  
  236.  
  237. do_plot(plots, pcount, min_x, max_x, min_y, max_y)
  238. struct curve_points *plots;
  239. int pcount;            /* count of plots in linked list */
  240. double min_x, max_x;
  241. double min_y, max_y;
  242. {
  243. register struct termentry *t = &term_tbl[term];
  244. register int curve, xaxis_y, yaxis_x;
  245. register struct curve_points *this_plot;
  246. register double ytic, xtic;
  247. register int xl, yl;
  248.             /* only a Pyramid would have this many registers! */
  249. double xtemp, ytemp;
  250. struct text_label *this_label;
  251. struct arrow_def *this_arrow;
  252. TBOOLEAN scaling;
  253.  
  254.  
  255. /* store these in variables global to this file */
  256. /* otherwise, we have to pass them around a lot */
  257.      x_min = min_x;
  258.      x_max = max_x; 
  259.      y_min = min_y;
  260.      y_max = max_y;
  261.  
  262.     if (polar) {
  263.         /* will possibly change x_min, x_max, y_min, y_max */
  264.         polar_xform(plots,pcount);
  265.     }
  266.  
  267.     if (y_min == VERYLARGE || y_max == -VERYLARGE ||
  268.         x_min == VERYLARGE || x_max == -VERYLARGE)
  269.         int_error("all points undefined!", NO_CARET);
  270.  
  271. /*    Apply the desired viewport offsets. */
  272.      if (y_min < y_max) {
  273.         y_min -= boff;
  274.         y_max += toff;
  275.     } else {
  276.         y_max -= boff;
  277.         y_min += toff;
  278.     }
  279.      if (x_min < x_max) {
  280.         x_min -= loff;
  281.         x_max += roff;
  282.     } else {
  283.         x_max -= loff;
  284.         x_min += roff;
  285.     }
  286.  
  287. /* SETUP RANGES, SCALES AND TIC PLACES */
  288.     if (ytics && yticdef.type == TIC_COMPUTED) {
  289.        ytic = make_tics(y_min,y_max,is_log_y,base_log_y);
  290.     
  291.        if (autoscale_ly) {
  292.           if (y_min < y_max) {
  293.              y_min = ytic * floor(y_min/ytic);       
  294.              y_max = ytic * ceil(y_max/ytic);
  295.           }
  296.           else {            /* reverse axis */
  297.              y_min = ytic * ceil(y_min/ytic);       
  298.              y_max = ytic * floor(y_max/ytic);
  299.           }
  300.        }
  301.     }
  302.  
  303.     if (xtics && xticdef.type == TIC_COMPUTED) {
  304.        xtic = make_tics(x_min,x_max,is_log_x,base_log_x);
  305.        
  306.        if (autoscale_lx) {
  307.           if (x_min < x_max) {
  308.              x_min = xtic * floor(x_min/xtic);    
  309.              x_max = xtic * ceil(x_max/xtic);
  310.           } else {
  311.              x_min = xtic * ceil(x_min/xtic);
  312.              x_max = xtic * floor(x_max/xtic);    
  313.           }
  314.        }
  315.     }
  316.  
  317. /*    This used be x_max == x_min, but that caused an infinite loop once. */
  318.     if (fabs(x_max - x_min) < zero)
  319.         int_error("x_min should not equal x_max!",NO_CARET);
  320.     if (fabs(y_max - y_min) < zero)
  321.         int_error("y_min should not equal y_max!",NO_CARET);
  322.  
  323. /* INITIALIZE TERMINAL */
  324.     if (!term_init) {
  325.         (*t->init)();
  326.         term_init = TRUE;
  327.     }
  328.     screen_ok = FALSE;
  329.     scaling = (*t->scale)(xsize, ysize);
  330.     (*t->graphics)();
  331.  
  332.      /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  333.      boundary(scaling);
  334.  
  335. /* SCALE FACTORS */
  336.     yscale = (ytop - ybot)/(y_max - y_min);
  337.     xscale = (xright - xleft)/(x_max - x_min);
  338.     
  339. /* DRAW AXES */
  340.     (*t->linetype)(-1);    /* axis line type */
  341.     xaxis_y = map_y(0.0);
  342.     yaxis_x = map_x(0.0); 
  343.  
  344.     if (xaxis_y < ybot)
  345.         xaxis_y = ybot;                /* save for impulse plotting */
  346.     else if (xaxis_y >= ytop)
  347.         xaxis_y = ytop ;
  348.     else if (xzeroaxis && !is_log_y) {
  349.         (*t->move)(xleft,xaxis_y);
  350.         (*t->vector)(xright,xaxis_y);
  351.     }
  352.  
  353.     if (yzeroaxis && !is_log_x && yaxis_x >= xleft && yaxis_x < xright ) {
  354.         (*t->move)(yaxis_x,ybot);
  355.         (*t->vector)(yaxis_x,ytop);
  356.     }
  357.  
  358. /* DRAW TICS */
  359.     (*t->linetype)(-2); /* border linetype */
  360.  
  361.     /* label y axis tics */
  362.      if (ytics) {
  363.         switch (yticdef.type) {
  364.            case TIC_COMPUTED: {
  365.                if (y_min < y_max)
  366.                 draw_ytics(ytic * floor(y_min/ytic),
  367.                         ytic,
  368.                         ytic * ceil(y_max/ytic));
  369.               else
  370.                 draw_ytics(ytic * floor(y_max/ytic),
  371.                         ytic,
  372.                         ytic * ceil(y_min/ytic));
  373.  
  374.               break;
  375.            }
  376.             case TIC_MONTH:{
  377.             draw_month_ytics();
  378.             break;
  379.             }
  380.             case TIC_DAY: {
  381.             draw_day_ytics();
  382.             break;
  383.             }
  384.            case TIC_SERIES: {
  385.               draw_series_ytics(yticdef.def.series.start, 
  386.                             yticdef.def.series.incr, 
  387.                             yticdef.def.series.end);
  388.               break;
  389.            }
  390.            case TIC_USER: {
  391.               draw_set_ytics(yticdef.def.user);
  392.               break;
  393.            }
  394.            default: {
  395.               (*t->text)();
  396.                 (void) fflush(outfile);
  397.               int_error("unknown tic type in yticdef in do_plot", NO_CARET);
  398.               break;        /* NOTREACHED */
  399.            }
  400.         }
  401.     }
  402.  
  403.     /* label x axis tics */
  404.      if (xtics) {
  405.         switch (xticdef.type) {
  406.            case TIC_COMPUTED: {
  407.                if (x_min < x_max)
  408.                 draw_xtics(xtic * floor(x_min/xtic),
  409.                         xtic,
  410.                         xtic * ceil(x_max/xtic));
  411.               else
  412.                 draw_xtics(xtic * floor(x_max/xtic),
  413.                         xtic,
  414.                         xtic * ceil(x_min/xtic));
  415.  
  416.               break;
  417.            }
  418.             case TIC_MONTH: {
  419.             draw_month_xtics();
  420.             break;
  421.             }
  422.             case TIC_DAY : {
  423.             draw_day_xtics();
  424.             break;
  425.             }
  426.            case TIC_SERIES: {
  427.               draw_series_xtics(xticdef.def.series.start, 
  428.                             xticdef.def.series.incr, 
  429.                             xticdef.def.series.end);
  430.               break;
  431.            }
  432.            case TIC_USER: {
  433.               draw_set_xtics(xticdef.def.user);
  434.               break;
  435.            }
  436.            default: {
  437.               (*t->text)();
  438.               (void) fflush(outfile);
  439.               int_error("unknown tic type in xticdef in do_plot", NO_CARET);
  440.               break;        /* NOTREACHED */
  441.            }
  442.         }
  443.     }
  444.  
  445. /* DRAW PLOT BORDER */
  446.     (*t->linetype)(-2); /* border linetype */
  447.     if (draw_border) {
  448.         (*t->move)(xleft,ybot);
  449.         (*t->vector)(xright,ybot);
  450.         (*t->vector)(xright,ytop);
  451.         (*t->vector)(xleft,ytop);
  452.         (*t->vector)(xleft,ybot);
  453.     }
  454.  
  455. /* PLACE YLABEL */
  456.     if (strlen(ylabel) > 0) {
  457.         int x, y;
  458.  
  459.         x = ylabel_xoffset * t->h_char;
  460.         y = ylabel_yoffset * t->v_char;
  461.         if ((*t->text_angle)(1)) {
  462.             if ((*t->justify_text)(CENTRE)) {
  463.                 (*t->put_text)(x+(t->v_char),
  464.                          y+(ytop+ybot)/2, ylabel);
  465.             }
  466.             else {
  467.                 (*t->put_text)(x+(t->v_char),
  468.                            y+(ytop+ybot)/2-(t->h_char)*strlen(ylabel)/2, 
  469.                          ylabel);
  470.             }
  471.         }
  472.         else {
  473.             (void)(*t->justify_text)(LEFT);
  474.             (*t->put_text)(x,y+ytop+(t->v_char), ylabel);
  475.         }
  476.         (void)(*t->text_angle)(0);
  477.     }
  478.  
  479. /* PLACE XLABEL */
  480.     if (strlen(xlabel) > 0) {
  481.         int x, y;
  482.  
  483.         x = xlabel_xoffset * t->h_char;
  484.         y = xlabel_yoffset * t->v_char;
  485.  
  486.             if ((*t->justify_text)(CENTRE)) 
  487.             (*t->put_text)(x+(xleft+xright)/2,
  488.                        y+ybot-2*(t->v_char), xlabel);
  489.             else
  490.             (*t->put_text)(x+(xleft+xright)/2 - strlen(xlabel)*(t->h_char)/2,
  491.                            y+ybot-2*(t->v_char), xlabel);
  492.     }
  493.  
  494. /* PLACE TITLE */
  495.     if (strlen(title) > 0) {
  496.         int x, y;
  497.  
  498.         x = title_xoffset * t->h_char;
  499.         y = title_yoffset * t->v_char;
  500.  
  501.             if ((*t->justify_text)(CENTRE))
  502.             (*t->put_text)(x+(xleft+xright)/2,
  503.                        y+ytop+(t->v_char), title);
  504.             else
  505.             (*t->put_text)(x+(xleft+xright)/2 - strlen(title)*(t->h_char)/2,
  506.                        y+ytop+(t->v_char), title);
  507.     }
  508.  
  509.  
  510. /* PLACE TIMEDATE */
  511.     if (timedate) {
  512.         int x, y;
  513.  
  514.         x = time_xoffset * t->h_char;
  515.         y = time_yoffset * t->v_char;
  516.         dated = time( (time_t *) 0);
  517.         tdate = ctime( &dated);
  518.         tdate[24]='\0';
  519.         (void)(*t->justify_text)(LEFT);
  520.         if ((*t->text_angle)(1)) {
  521.             (void)(*t->text_angle)(0);
  522.             (*t->put_text)(x, y+ytop+(t->v_char), tdate);
  523.         }
  524.         else {
  525.             (void)(*t->text_angle)(0);
  526.             (*t->put_text)(x,
  527.                          y+ybot-3*(t->v_char), tdate);
  528.         }
  529.     }
  530.  
  531. /* PLACE LABELS */
  532.     for (this_label = first_label; this_label!=NULL;
  533.             this_label=this_label->next ) {
  534.          xtemp = LogScale(this_label->x, is_log_x, log_base_log_x, "label", "x");
  535.          ytemp = LogScale(this_label->y, is_log_y, log_base_log_y, "label", "y");
  536.         if ((*t->justify_text)(this_label->pos)) {
  537.             (*t->put_text)(map_x(xtemp),map_y(ytemp),this_label->text);
  538.         }
  539.         else {
  540.             switch(this_label->pos) {
  541.                 case  LEFT:
  542.                     (*t->put_text)(map_x(xtemp),map_y(ytemp),
  543.                         this_label->text);
  544.                     break;
  545.                 case CENTRE:
  546.                     (*t->put_text)(map_x(xtemp)-
  547.                         (t->h_char)*strlen(this_label->text)/2,
  548.                         map_y(ytemp), this_label->text);
  549.                     break;
  550.                 case RIGHT:
  551.                     (*t->put_text)(map_x(xtemp)-
  552.                         (t->h_char)*strlen(this_label->text),
  553.                         map_y(ytemp), this_label->text);
  554.                     break;
  555.             }
  556.          }
  557.      }
  558.  
  559. /* PLACE ARROWS */
  560.     (*t->linetype)(0);    /* arrow line type */
  561.     for (this_arrow = first_arrow; this_arrow!=NULL;
  562.         this_arrow = this_arrow->next ) {
  563.        int sx = map_x(LogScale(this_arrow->sx, is_log_x, log_base_log_x, "arrow", "x"));
  564.        int sy = map_y(LogScale(this_arrow->sy, is_log_y, log_base_log_y, "arrow", "y"));
  565.        int ex = map_x(LogScale(this_arrow->ex, is_log_x, log_base_log_x, "arrow", "x"));
  566.        int ey = map_y(LogScale(this_arrow->ey, is_log_y, log_base_log_y, "arrow", "y"));
  567.        
  568.        (*t->arrow)(sx, sy, ex, ey, this_arrow->head);
  569.     }
  570.  
  571.  
  572. /* DRAW CURVES */
  573.     if (key == -1) {
  574.         xl = xright  - (t->h_tic) - (t->h_char)*5;
  575.         yl = ytop - (t->v_tic) - (t->v_char);
  576.     }
  577.     if (key == 1) {
  578.         xl = map_x( LogScale(key_x, is_log_x, log_base_log_x, "key", "x") );
  579.         yl = map_y( LogScale(key_y, is_log_y, log_base_log_y, "key", "y") );
  580.     }
  581.  
  582.     this_plot = plots;
  583.     for (curve = 0; curve < pcount; this_plot = this_plot->next_cp, curve++) {
  584.         int oldkey = key;
  585.  
  586.         if (this_plot->title && !*this_plot->title) {
  587.             key = 0;
  588.         } else {
  589.         (*t->linetype)(this_plot->line_type);
  590.         if (key != 0 && this_plot->title) {
  591.             if ((*t->justify_text)(RIGHT)) {
  592.                 (*t->put_text)(xl,
  593.                     yl,this_plot->title);
  594.             }
  595.             else {
  596.                 if (inrange(xl-(t->h_char)*strlen(this_plot->title), 
  597.                          xleft, xright))
  598.                  (*t->put_text)(xl-(t->h_char)*strlen(this_plot->title),
  599.                              yl,this_plot->title);
  600.             }
  601.         }
  602.         }
  603.  
  604.         switch(this_plot->plot_style) {
  605.             case IMPULSES: {
  606.                if (key != 0 && this_plot->title) {
  607.                   (*t->move)(xl+(t->h_char),yl);
  608.                   (*t->vector)(xl+4*(t->h_char),yl);
  609.                }
  610.                plot_impulses(this_plot, yaxis_x, xaxis_y);
  611.                break;
  612.             }
  613.             case LINES: {
  614.                if (key != 0 && this_plot->title) {
  615.                   (*t->move)(xl+(int)(t->h_char),yl);
  616.                   (*t->vector)(xl+(int)(4*(t->h_char)),yl);
  617.                }
  618.                plot_lines(this_plot);
  619.                break;
  620.             }
  621. /* JG */        case STEPS: {
  622.                if (key != 0 && this_plot->title) {
  623.                   (*t->move)(xl+(int)(t->h_char),yl);
  624.                   (*t->vector)(xl+(int)(4*(t->h_char)),yl);
  625.                }
  626.                plot_steps(this_plot);
  627.                break;
  628.             }
  629.             case POINTSTYLE: {
  630.                if (key != 0 && this_plot->title) {
  631.                   (*t->point)(xl+2*(t->h_char),yl,
  632.                             this_plot->point_type);
  633.                }
  634.                plot_points(this_plot);
  635.                break;
  636.             }
  637.             case LINESPOINTS: {
  638.                /* put lines */
  639.                if (key != 0 && this_plot->title) {
  640.                   (*t->move)(xl+(t->h_char),yl);
  641.                   (*t->vector)(xl+4*(t->h_char),yl);
  642.                }
  643.                plot_lines(this_plot);
  644.  
  645.                /* put points */
  646.                if (key != 0 && this_plot->title) {
  647.                   (*t->point)(xl+2*(t->h_char),yl,
  648.                             this_plot->point_type);
  649.                }
  650.                plot_points(this_plot);
  651.                break;
  652.             }
  653.             case DOTS: {
  654.                if (key != 0 && this_plot->title) {
  655.                   (*t->point)(xl+2*(t->h_char),yl, -1);
  656.                }
  657.                plot_dots(this_plot);
  658.                break;
  659.             }
  660.             case ERRORBARS: {
  661.                if (key != 0 && this_plot->title) {
  662.                   (*t->point)(xl+2*(t->h_char),yl,
  663.                             this_plot->point_type);
  664.                }
  665.                plot_points(this_plot);
  666.  
  667.                /* for functions, just like POINTSTYLE */
  668.                if (this_plot->plot_type == DATA) {
  669.                   if (key != 0 && this_plot->title) {
  670.                      (*t->move)(xl+(t->h_char),yl);
  671.                      (*t->vector)(xl+4*(t->h_char),yl);
  672.                      (*t->move)(xl+(t->h_char),yl+ERRORBARTIC);
  673.                      (*t->vector)(xl+(t->h_char),yl-ERRORBARTIC);
  674.                      (*t->move)(xl+4*(t->h_char),yl+ERRORBARTIC);
  675.                      (*t->vector)(xl+4*(t->h_char),yl-ERRORBARTIC);
  676.                   }
  677.                   plot_bars(this_plot);
  678.                }
  679.                break;
  680.             }
  681.             case BOXERROR: {
  682.                if (this_plot->plot_type == DATA) {
  683.                   if (key != 0 && this_plot->title) {
  684.                      (*t->move)(xl+(t->h_char),yl+ERRORBARTIC);
  685.                      (*t->vector)(xl+(t->h_char),yl-ERRORBARTIC);
  686.                      (*t->move)(xl+4*(t->h_char),yl+ERRORBARTIC);
  687.                      (*t->vector)(xl+4*(t->h_char),yl-ERRORBARTIC);
  688.                   }
  689.                   plot_bars(this_plot);
  690.                }
  691.             }
  692.             /* no break */
  693.             case BOXES: {
  694.                if (key != 0 && this_plot->title) {
  695.                   (*t->move)(xl+(t->h_char),yl);
  696.                   (*t->vector)(xl+4*(t->h_char),yl);
  697.                }
  698.                plot_boxes(this_plot,xaxis_y);
  699.                break;
  700.             }
  701.  
  702.         }
  703.         if (key && this_plot->title) {
  704.             yl = yl - (t->v_char);
  705.         }
  706.         key = oldkey;
  707.     }
  708.     (*t->text)();
  709.     (void) fflush(outfile);
  710. }
  711.  
  712. /* plot_impulses:
  713.  * Plot the curves in IMPULSES style
  714.  */
  715. void
  716. plot_impulses(plot, yaxis_x, xaxis_y)
  717.     struct curve_points *plot;
  718.     int yaxis_x, xaxis_y;
  719. {
  720.     int i;
  721.     int x,y;
  722.     struct termentry *t = &term_tbl[term];
  723.  
  724.     for (i = 0; i < plot->p_count; i++) {
  725.        switch (plot->points[i].type) {
  726.           case INRANGE: {
  727.              x = map_x(plot->points[i].x);
  728.              y = map_y(plot->points[i].y);
  729.              break;
  730.           }
  731.           case OUTRANGE: {
  732.              if (!inrange(plot->points[i].x, x_min,x_max))
  733.                continue;
  734.              x = map_x(plot->points[i].x);
  735.              if ((y_min < y_max 
  736.                  && plot->points[i].y < y_min)
  737.                 || (y_max < y_min 
  738.                     && plot->points[i].y > y_min))
  739.                y = map_y(y_min);
  740.              if ((y_min < y_max 
  741.                  && plot->points[i].y > y_max)
  742.                 || (y_max<y_min 
  743.                     && plot->points[i].y < y_max))
  744.                y = map_y(y_max);
  745.              break;
  746.           }
  747.           default:        /* just a safety */
  748.           case UNDEFINED: {
  749.              continue;
  750.           }
  751.        }
  752.                     
  753.        if (polar)
  754.           (*t->move)(yaxis_x,xaxis_y);
  755.        else
  756.           (*t->move)(x,xaxis_y);
  757.        (*t->vector)(x,y);
  758.     }
  759.  
  760. }
  761.  
  762. /* plot_lines:
  763.  * Plot the curves in LINES style
  764.  */
  765. void
  766. plot_lines(plot)
  767.     struct curve_points *plot;
  768. {
  769.     int i;                /* point index */
  770.     int x,y;                /* point in terminal coordinates */
  771.     struct termentry *t = &term_tbl[term];
  772.     enum coord_type prev = UNDEFINED; /* type of previous point */
  773.     double ex, ey;            /* an edge point */
  774.     double lx[2], ly[2];        /* two edge points */
  775.  
  776.     for (i = 0; i < plot->p_count; i++) {
  777.        switch (plot->points[i].type) {
  778.           case INRANGE: {
  779.              x = map_x(plot->points[i].x);
  780.              y = map_y(plot->points[i].y);
  781.  
  782.              if (prev == INRANGE) {
  783.                 (*t->vector)(x,y);
  784.              } else if (prev == OUTRANGE) {
  785.                 /* from outrange to inrange */
  786.                 if (!clip_lines1) {
  787.                     (*t->move)(x,y);
  788.                 } else {
  789.                     edge_intersect(plot->points, i, &ex, &ey);
  790.                     (*t->move)(map_x(ex), map_y(ey));
  791.                     (*t->vector)(x,y);
  792.                 }
  793.              } else {        /* prev == UNDEFINED */
  794.                 (*t->move)(x,y);
  795.                 (*t->vector)(x,y);
  796.              }
  797.                     
  798.              break;
  799.           }
  800.           case OUTRANGE: {
  801.              if (prev == INRANGE) {
  802.                 /* from inrange to outrange */
  803.                 if (clip_lines1) {
  804.                     edge_intersect(plot->points, i, &ex, &ey);
  805.                     (*t->vector)(map_x(ex), map_y(ey));
  806.                 }
  807.              } else if (prev == OUTRANGE) {
  808.                 /* from outrange to outrange */
  809.                 if (clip_lines2) {
  810.                     if (two_edge_intersect(plot->points, i, lx, ly)) {
  811.                        (*t->move)(map_x(lx[0]), map_y(ly[0]));
  812.                        (*t->vector)(map_x(lx[1]), map_y(ly[1]));
  813.                     }
  814.                 }
  815.              }
  816.              break;
  817.           }
  818.           default:        /* just a safety */
  819.           case UNDEFINED: {
  820.              break;
  821.           }
  822.        }
  823.        prev = plot->points[i].type;
  824.     }
  825. }
  826.  
  827. /* XXX - JG  */
  828. /* plot_steps:                
  829.  * Plot the curves in STEPS style
  830.  */
  831. void
  832. plot_steps(plot)
  833. struct curve_points *plot;
  834. {
  835.     int i;                /* point index */
  836.     int x,y;                /* point in terminal coordinates */
  837.     struct termentry *t = &term_tbl[term];
  838.     enum coord_type prev = UNDEFINED;    /* type of previous point */
  839.     double ex, ey;            /* an edge point */
  840.     double lx[2], ly[2];        /* two edge points */
  841.     int xprev, yprev;            /* previous point coordinates */
  842.  
  843.     for (i = 0; i < plot->p_count; i++) {
  844.        switch (plot->points[i].type) {
  845.           case INRANGE: {
  846.              x = map_x(plot->points[i].x);
  847.              y = map_y(plot->points[i].y);
  848.  
  849.              if (prev == INRANGE) {
  850.                 (*t->vector)(x,yprev);
  851.                 (*t->vector)(x,y);
  852.              } else if (prev == OUTRANGE) {
  853.                 /* from outrange to inrange */
  854.                 if (!clip_lines1) {
  855.                     (*t->move)(x,y);
  856.                 } else {        /* find edge intersection */
  857.                     edge_intersect_steps(plot->points, i, &ex, &ey);
  858.                     (*t->move)(map_x(ex), map_y(ey));
  859.                     (*t->vector)(x,map_y(ey));
  860.                     (*t->vector)(x,y);
  861.                 }
  862.              } else {        /* prev == UNDEFINED */
  863.                 (*t->move)(x,y);
  864.                 (*t->vector)(x,y);
  865.              }
  866.              break;
  867.           }
  868.           case OUTRANGE: {
  869.              if (prev == INRANGE) {
  870.                 /* from inrange to outrange */
  871.                 if (clip_lines1) {
  872.                     edge_intersect_steps(plot->points, i, &ex, &ey);
  873.                     (*t->vector)(map_x(ex), yprev);
  874.                     (*t->vector)(map_x(ex), map_y(ey));
  875.                 }
  876.              } else if (prev == OUTRANGE) {
  877.                 /* from outrange to outrange */
  878.                 if (clip_lines2) {
  879.                     if (two_edge_intersect_steps(plot->points, i, lx, ly)) {
  880.                        (*t->move)(map_x(lx[0]), map_y(ly[0]));
  881.                        (*t->vector)(map_x(lx[1]), map_y(ly[0]));
  882.                        (*t->vector)(map_x(lx[1]), map_y(ly[1]));
  883.                     }
  884.                 }
  885.              }
  886.              break;
  887.           }
  888.           default:        /* just a safety */
  889.           case UNDEFINED: {
  890.              break;
  891.           }
  892.        }
  893.        prev  = plot->points[i].type;
  894.        xprev = x;
  895.        yprev = y;
  896.     }
  897. }
  898.  
  899. /* plot_bars:
  900.  * Plot the curves in ERRORBARS style
  901.  *  we just plot the bars; the points are plotted in plot_points
  902.  */
  903. void
  904. plot_bars(plot)
  905.     struct curve_points *plot;
  906. {
  907.     int i;                /* point index */
  908.     struct termentry *t = &term_tbl[term];
  909.     double x;                /* position of the bar */
  910.     double ylow, yhigh;        /* the ends of the bars */
  911.     unsigned int xM, ylowM, yhighM; /* the mapped version of above */
  912.     TBOOLEAN low_inrange, high_inrange;
  913.     int tic = ERRORBARTIC;
  914.     
  915.     for (i = 0; i < plot->p_count; i++) {
  916.        /* undefined points don't count */
  917.        if (plot->points[i].type == UNDEFINED)
  918.         continue;
  919.  
  920.        /* check to see if in xrange */
  921.        x = plot->points[i].x;
  922.        if (! inrange(x, x_min, x_max))
  923.         continue;
  924.        xM = map_x(x);
  925.  
  926.        /* find low and high points of bar, and check yrange */
  927.        yhigh = plot->points[i].yhigh;
  928.        ylow = plot->points[i].ylow;
  929.  
  930.        high_inrange = inrange(yhigh, y_min,y_max);
  931.        low_inrange = inrange(ylow, y_min,y_max);
  932.  
  933.        /* compute the plot position of yhigh */
  934.        if (high_inrange)
  935.         yhighM = map_y(yhigh);
  936.        else if (samesign(yhigh-y_max, y_max-y_min))
  937.         yhighM = map_y(y_max);
  938.        else
  939.         yhighM = map_y(y_min);
  940.        
  941.        /* compute the plot position of ylow */
  942.        if (low_inrange)
  943.         ylowM = map_y(ylow);
  944.        else if (samesign(ylow-y_max, y_max-y_min))
  945.         ylowM = map_y(y_max);
  946.        else
  947.         ylowM = map_y(y_min);
  948.  
  949.        if (!high_inrange && !low_inrange && ylowM == yhighM)
  950.         /* both out of range on the same side */
  951.           continue;
  952.  
  953.        /* by here everything has been mapped */
  954.        (*t->move)(xM, ylowM);
  955.        (*t->vector)(xM, yhighM); /* draw the main bar */
  956.        (*t->move)(xM-tic, ylowM); /* draw the bottom tic */
  957.        (*t->vector)(xM+tic, ylowM);
  958.        (*t->move)(xM-tic, yhighM); /* draw the top tic */
  959.        (*t->vector)(xM+tic, yhighM);
  960.     }
  961. }
  962.  
  963. /* plot_boxes:
  964.  * Plot the curves in BOXES style
  965.  */
  966. void
  967. plot_boxes(plot,xaxis_y)
  968.     struct curve_points *plot;
  969.     int xaxis_y;
  970. {
  971.     int i;                /* point index */
  972.     int xl,xr,yt;            /* point in terminal coordinates */
  973.     double dxl,dxr,dyt;
  974.     struct termentry *t = &term_tbl[term];
  975.     enum coord_type prev = UNDEFINED; /* type of previous point */
  976.  
  977.     for (i = 0; i < plot->p_count; i++) {
  978.        switch (plot->points[i].type) {
  979.           case OUTRANGE:
  980.           case INRANGE: {
  981.             if (plot->points[i].z<0.0) {
  982.                if (boxwidth<0.0) {
  983.                     /* calculate width */
  984.                     if (prev!=UNDEFINED)
  985.                         dxl = (plot->points[i-1].x - plot->points[i].x)/2.0;
  986.                     else
  987.                         dxl = 0.0;
  988.                     if (i < plot->p_count-1) {
  989.                         if (plot->points[i+1].type!=UNDEFINED)
  990.                             dxr = (plot->points[i+1].x - plot->points[i].x)/2.0;
  991.                         else
  992.                             dxr = -dxl;
  993.                     }
  994.                     else {
  995.                         dxr = -dxl;
  996.                     }
  997.                     if (prev==UNDEFINED)
  998.                         dxl = -dxr;
  999.                 }
  1000.                 else {
  1001.                     dxr = boxwidth/2.0;
  1002.                     dxl = -dxr;
  1003.                 }
  1004.             }
  1005.             else {
  1006.                 dxr = plot->points[i].z/2.0;
  1007.                 dxl = -dxr;
  1008.             }
  1009.  
  1010.             dxl= plot->points[i].x+dxl;
  1011.             dxr= plot->points[i].x+dxr;
  1012.             dyt= plot->points[i].y;
  1013.  
  1014.             /* clip to border */
  1015.             if ((y_min < y_max  && dyt < y_min)
  1016.                 || (y_max < y_min  && dyt > y_min))
  1017.                dyt = y_min;
  1018.             if ((y_min < y_max  && dyt > y_max)
  1019.                 || (y_max<y_min  && dyt < y_max))
  1020.                dyt = y_max;
  1021.             if ((x_min < x_max  && dxr < x_min)
  1022.                 || (x_max < x_min  && dxr > x_min))
  1023.                dxr = x_min;
  1024.             if ((x_min < x_max  && dxr > x_max)
  1025.                 || (x_max<x_min  && dxr < x_max))
  1026.                dxr = x_max;
  1027.             if ((x_min < x_max  && dxl < x_min)
  1028.                 || (x_max < x_min  && dxl > x_min))
  1029.                dxl = x_min;
  1030.             if ((x_min < x_max  && dxl > x_max)
  1031.                 || (x_max<x_min  && dxl < x_max))
  1032.                dxl = x_max;
  1033.  
  1034.             xl= map_x(dxl);
  1035.             xr= map_x(dxr);
  1036.             yt = map_y(dyt);
  1037.  
  1038.             (*t->move)(xl,xaxis_y);
  1039.             (*t->vector)(xl,yt);
  1040.             (*t->vector)(xr,yt);
  1041.             (*t->vector)(xr,xaxis_y);
  1042.             (*t->vector)(xl,xaxis_y);
  1043.             break;
  1044.           }
  1045.           default:        /* just a safety */
  1046.           case UNDEFINED: {
  1047.              break;
  1048.           }
  1049.        }
  1050.        prev = plot->points[i].type;
  1051.     }
  1052. }
  1053.  
  1054. /* plot_points:
  1055.  * Plot the curves in POINTSTYLE style
  1056.  */
  1057. void
  1058. plot_points(plot)
  1059.     struct curve_points *plot;
  1060. {
  1061.     int i;
  1062.     int x,y;
  1063.     struct termentry *t = &term_tbl[term];
  1064.  
  1065.     for (i = 0; i < plot->p_count; i++) {
  1066.        if (plot->points[i].type == INRANGE) {
  1067.           x = map_x(plot->points[i].x);
  1068.           y = map_y(plot->points[i].y);
  1069.           /* do clipping if necessary */
  1070.           if (!clip_points ||
  1071.              (   x >= xleft + t->h_tic  && y >= ybot + t->v_tic 
  1072.               && x <= xright - t->h_tic && y <= ytop - t->v_tic))
  1073.             (*t->point)(x,y, plot->point_type);
  1074.        }
  1075.     }
  1076. }
  1077.  
  1078. /* plot_dots:
  1079.  * Plot the curves in DOTS style
  1080.  */
  1081. void
  1082. plot_dots(plot)
  1083.     struct curve_points *plot;
  1084. {
  1085.     int i;
  1086.     int x,y;
  1087.     struct termentry *t = &term_tbl[term];
  1088.  
  1089.     for (i = 0; i < plot->p_count; i++) {
  1090.        if (plot->points[i].type == INRANGE) {
  1091.           x = map_x(plot->points[i].x);
  1092.           y = map_y(plot->points[i].y);
  1093.           /* point type -1 is a dot */
  1094.           (*t->point)(x,y, -1);
  1095.        }
  1096.     }
  1097. }
  1098.  
  1099. /* single edge intersection algorithm */
  1100. /* Given two points, one inside and one outside the plot, return
  1101.  * the point where an edge of the plot intersects the line segment defined 
  1102.  * by the two points.
  1103.  */
  1104. void
  1105. edge_intersect(points, i, ex, ey)
  1106.     struct coordinate GPHUGE *points; /* the points array */
  1107.     int i;                /* line segment from point i-1 to point i */
  1108.     double *ex, *ey;        /* the point where it crosses an edge */
  1109. {
  1110.     /* global x_min, x_max, y_min, x_max */
  1111.     double ax = points[i-1].x;
  1112.     double ay = points[i-1].y;
  1113.     double bx = points[i].x;
  1114.     double by = points[i].y;
  1115.     double x, y;            /* possible intersection point */
  1116.  
  1117.     if (by == ay) {
  1118.        /* horizontal line */
  1119.        /* assume inrange(by, y_min, y_max) */
  1120.        *ey = by;        /* == ay */
  1121.  
  1122.        if (inrange(x_max, ax, bx))
  1123.         *ex = x_max;
  1124.        else if (inrange(x_min, ax, bx))
  1125.         *ex = x_min;
  1126.        else {
  1127.         (*term_tbl[term].text)();
  1128.         (void) fflush(outfile);
  1129.         int_error("error in edge_intersect", NO_CARET);
  1130.        }
  1131.        return;
  1132.     } else if (bx == ax) {
  1133.        /* vertical line */
  1134.        /* assume inrange(bx, x_min, x_max) */
  1135.        *ex = bx;        /* == ax */
  1136.  
  1137.        if (inrange(y_max, ay, by))
  1138.         *ey = y_max;
  1139.        else if (inrange(y_min, ay, by))
  1140.         *ey = y_min;
  1141.        else {
  1142.         (*term_tbl[term].text)();
  1143.         (void) fflush(outfile);
  1144.         int_error("error in edge_intersect", NO_CARET);
  1145.        }
  1146.        return;
  1147.     }
  1148.  
  1149.     /* slanted line of some kind */
  1150.  
  1151.     /* does it intersect y_min edge */
  1152.     if (inrange(y_min, ay, by) && y_min != ay && y_min != by) {
  1153.        x = ax + (y_min-ay) * ((bx-ax) / (by-ay));
  1154.        if (inrange(x, x_min, x_max)) {
  1155.           *ex = x;
  1156.           *ey = y_min;
  1157.           return;            /* yes */
  1158.        }
  1159.     }
  1160.     
  1161.     /* does it intersect y_max edge */
  1162.     if (inrange(y_max, ay, by) && y_max != ay && y_max != by) {
  1163.        x = ax + (y_max-ay) * ((bx-ax) / (by-ay));
  1164.        if (inrange(x, x_min, x_max)) {
  1165.           *ex = x;
  1166.           *ey = y_max;
  1167.           return;            /* yes */
  1168.        }
  1169.     }
  1170.  
  1171.     /* does it intersect x_min edge */
  1172.     if (inrange(x_min, ax, bx) && x_min != ax && x_min != bx) {
  1173.        y = ay + (x_min-ax) * ((by-ay) / (bx-ax));
  1174.        if (inrange(y, y_min, y_max)) {
  1175.           *ex = x_min;
  1176.           *ey = y;
  1177.           return;
  1178.        }
  1179.     }
  1180.  
  1181.     /* does it intersect x_max edge */
  1182.     if (inrange(x_max, ax, bx) && x_max != ax && x_max != bx) {
  1183.        y = ay + (x_max-ax) * ((by-ay) / (bx-ax));
  1184.        if (inrange(y, y_min, y_max)) {
  1185.           *ex = x_max;
  1186.           *ey = y;
  1187.           return;
  1188.        }
  1189.     }
  1190.  
  1191.     /* It is possible for one or two of the [ab][xy] values to be -VERYLARGE.
  1192.     * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned 
  1193.     * FALSE above. Otherwise we fall through all the tests above. 
  1194.     * If two are -VERYLARGE, it is ax=ay=-VERYLARGE or bx=by=-VERYLARGE 
  1195.     * since either a or b must be INRANGE. 
  1196.     * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  1197.     * Handle them carefully here. As yet we have no way for them to be 
  1198.     * +VERYLARGE.
  1199.     */
  1200.     if (ax == -VERYLARGE) {
  1201.        if (ay != -VERYLARGE) {
  1202.           *ex = min(x_min, x_max);
  1203.           *ey = by;
  1204.           return;
  1205.        }
  1206.     } else if (bx == -VERYLARGE) {
  1207.        if (by != -VERYLARGE) {
  1208.           *ex = min(x_min, x_max);
  1209.           *ey = ay;
  1210.           return;
  1211.        }
  1212.     } else if (ay == -VERYLARGE) {
  1213.        /* note we know ax != -VERYLARGE */
  1214.        *ex = bx;
  1215.        *ey = min(y_min, y_max);
  1216.        return;
  1217.     } else if (by == -VERYLARGE) {
  1218.        /* note we know bx != -VERYLARGE */
  1219.        *ex = ax;
  1220.        *ey = min(y_min, y_max);
  1221.        return;
  1222.     }
  1223.  
  1224.     /* If we reach here, then either one point is (-VERYLARGE,-VERYLARGE), 
  1225.     * or the inrange point is on the edge, and
  1226.      * the line segment from the outrange point does not cross any 
  1227.     * other edges to get there. In either case, we return the inrange 
  1228.     * point as the 'edge' intersection point. This will basically draw
  1229.     * line.
  1230.     */
  1231.     if (points[i].type == INRANGE) {
  1232.        *ex = bx; 
  1233.        *ey = by;
  1234.     } else {
  1235.        *ex = ax; 
  1236.        *ey = ay;
  1237.     }
  1238.     return;
  1239. }
  1240.  
  1241. /* XXX - JG  */
  1242. /* single edge intersection algorithm for "steps" curves */
  1243. /* 
  1244.  * Given two points, one inside and one outside the plot, return
  1245.  * the point where an edge of the plot intersects the line segments
  1246.  * forming the step between the two points. 
  1247.  *
  1248.  * Recall that if P1 = (x1,y1) and P2 = (x2,y2), the step from  
  1249.  * P1 to P2 is drawn as two line segments: (x1,y1)->(x2,y1) and 
  1250.  * (x2,y1)->(x2,y2). 
  1251.  */
  1252. void
  1253. edge_intersect_steps(points, i, ex, ey)
  1254.     struct coordinate *points; /* the points array */
  1255.     int i;                /* line segment from point i-1 to point i */
  1256.     double *ex, *ey;        /* the point where it crosses an edge */
  1257. {
  1258.     /* global x_min, x_max, y_min, x_max */
  1259.     double ax = points[i-1].x;
  1260.     double ay = points[i-1].y;
  1261.     double bx = points[i].x;
  1262.     double by = points[i].y;
  1263.  
  1264.     if (points[i].type == INRANGE) {    /* from OUTRANGE to INRANG */
  1265.         if (inrange(ay,y_min,y_max)) {
  1266.         *ey = ay;
  1267.         if (ax > x_max)
  1268.             *ex = x_max;
  1269.         else            /* x < x_min */
  1270.             *ex = x_min;
  1271.         } else {
  1272.             *ex = bx;
  1273.         if (ay > y_max)     
  1274.             *ey = y_max;
  1275.         else            /* y < y_min */
  1276.             *ey = y_min;
  1277.         }
  1278.     } else {                /* from INRANGE to OUTRANGE */
  1279.         if (inrange(bx,x_min,x_max)) {
  1280.         *ex = bx;
  1281.         if (by > y_max)
  1282.             *ey = y_max;
  1283.         else            /* y < y_min */
  1284.             *ey = y_min;
  1285.         } else {
  1286.             *ey = ay;
  1287.         if (bx > x_max)     
  1288.             *ex = x_max;
  1289.         else            /* x < x_min */
  1290.             *ex = x_min;
  1291.         }
  1292.     }
  1293.     return;
  1294. }
  1295.  
  1296. /* XXX - JG  */
  1297. /* double edge intersection algorithm for "steps" plot */
  1298. /* Given two points, both outside the plot, return the points where an 
  1299.  * edge of the plot intersects the line segments forming a step 
  1300.  * by the two points. There may be zero, one, two, or an infinite number
  1301.  * of intersection points. (One means an intersection at a corner, infinite
  1302.  * means overlaying the edge itself). We return FALSE when there is nothing
  1303.  * to draw (zero intersections), and TRUE when there is something to 
  1304.  * draw (the one-point case is a degenerate of the two-point case and we do 
  1305.  * not distinguish it - we draw it anyway).
  1306.  *
  1307.  * Recall that if P1 = (x1,y1) and P2 = (x2,y2), the step from  
  1308.  * P1 to P2 is drawn as two line segments: (x1,y1)->(x2,y1) and 
  1309.  * (x2,y1)->(x2,y2). 
  1310.  */
  1311. TBOOLEAN                /* any intersection? */
  1312. two_edge_intersect_steps(points, i, lx, ly)
  1313.     struct coordinate *points; /* the points array */
  1314.     int i;                /* line segment from point i-1 to point i */
  1315.     double *lx, *ly;        /* lx[2], ly[2]: points where it crosses edges */
  1316. {
  1317.     /* global x_min, x_max, y_min, x_max */
  1318.     double ax = points[i-1].x;
  1319.     double ay = points[i-1].y;
  1320.     double bx = points[i].x;
  1321.     double by = points[i].y;
  1322.  
  1323.     if ( max(ax,bx) < x_min || min(ax,bx) > x_max || 
  1324.          max(ay,by) < y_min || min(ay,by) > y_max ||
  1325.          ( (ay  > y_max || ay < y_min)            &&
  1326.            (bx  > x_max || bx < x_min)  ) ) {
  1327.     return(FALSE);                
  1328.     } else if (inrange(ay,y_min,y_max) && inrange(bx,x_min,x_max)) {    /* corner of step inside plotspace */
  1329.         *ly++ = ay;
  1330.     if (ax < x_min) 
  1331.         *lx++ = x_min;
  1332.     else 
  1333.         *lx++ = x_max;
  1334.  
  1335.     *lx++ = bx;
  1336.     if (by < x_min) 
  1337.         *ly++ = y_min;
  1338.     else 
  1339.         *ly++ = y_max;
  1340.  
  1341.     return(TRUE);
  1342.     } else if (inrange(ay,y_min,y_max)) {    /* cross plotspace in x-direction */
  1343.     *lx++ = x_min;
  1344.     *ly++ = ay;
  1345.     *lx++ = x_max;
  1346.     *ly++ = ay;
  1347.     return(TRUE);
  1348.     } else if (inrange(ax,x_min,x_max)) {    /* cross plotspace in y-direction */
  1349.     *lx++ = bx;
  1350.     *ly++ = y_min;
  1351.     *lx++ = bx;
  1352.     *ly++ = y_max;
  1353.     return(TRUE);
  1354.     } else
  1355.     return(FALSE);
  1356. }
  1357.  
  1358. /* double edge intersection algorithm */
  1359. /* Given two points, both outside the plot, return
  1360.  * the points where an edge of the plot intersects the line segment defined 
  1361.  * by the two points. There may be zero, one, two, or an infinite number
  1362.  * of intersection points. (One means an intersection at a corner, infinite
  1363.  * means overlaying the edge itself). We return FALSE when there is nothing
  1364.  * to draw (zero intersections), and TRUE when there is something to 
  1365.  * draw (the one-point case is a degenerate of the two-point case and we do 
  1366.  * not distinguish it - we draw it anyway).
  1367.  */
  1368. TBOOLEAN                /* any intersection? */
  1369. two_edge_intersect(points, i, lx, ly)
  1370.     struct coordinate GPHUGE *points; /* the points array */
  1371.     int i;                /* line segment from point i-1 to point i */
  1372.     double *lx, *ly;        /* lx[2], ly[2]: points where it crosses edges */
  1373. {
  1374.     /* global x_min, x_max, y_min, x_max */
  1375.     double ax = points[i-1].x;
  1376.     double ay = points[i-1].y;
  1377.     double bx = points[i].x;
  1378.     double by = points[i].y;
  1379.     double x, y;            /* possible intersection point */
  1380.     TBOOLEAN intersect = FALSE;
  1381.  
  1382.     if (by == ay) {
  1383.        /* horizontal line */
  1384.        /* y coord must be in range, and line must span both x_min and x_max */
  1385.        /* note that spanning x_min implies spanning x_max */
  1386.        if (inrange(by, y_min, y_max) && inrange(x_min, ax, bx)) {
  1387.           *lx++ = x_min;
  1388.           *ly++ = by;
  1389.           *lx++ = x_max;
  1390.           *ly++ = by;
  1391.           return(TRUE);
  1392.        } else
  1393.         return(FALSE);
  1394.     } else if (bx == ax) {
  1395.        /* vertical line */
  1396.        /* x coord must be in range, and line must span both y_min and y_max */
  1397.        /* note that spanning y_min implies spanning y_max */
  1398.        if (inrange(bx, x_min, x_max) && inrange(y_min, ay, by)) {
  1399.           *lx++ = bx;
  1400.           *ly++ = y_min;
  1401.           *lx++ = bx;
  1402.           *ly++ = y_max;
  1403.           return(TRUE);
  1404.        } else
  1405.         return(FALSE);
  1406.     }
  1407.  
  1408.     /* slanted line of some kind */
  1409.     /* there can be only zero or two intersections below */
  1410.  
  1411.     /* does it intersect y_min edge */
  1412.     if (inrange(y_min, ay, by)) {
  1413.        x = ax + (y_min-ay) * ((bx-ax) / (by-ay));
  1414.        if (inrange(x, x_min, x_max)) {
  1415.           *lx++ = x;
  1416.           *ly++ = y_min;
  1417.           intersect = TRUE;
  1418.        }
  1419.     }
  1420.     
  1421.     /* does it intersect y_max edge */
  1422.     if (inrange(y_max, ay, by)) {
  1423.        x = ax + (y_max-ay) * ((bx-ax) / (by-ay));
  1424.        if (inrange(x, x_min, x_max)) {
  1425.           *lx++ = x;
  1426.           *ly++ = y_max;
  1427.           intersect = TRUE;
  1428.        }
  1429.     }
  1430.  
  1431.     /* does it intersect x_min edge */
  1432.     if (inrange(x_min, ax, bx)) {
  1433.        y = ay + (x_min-ax) * ((by-ay) / (bx-ax));
  1434.        if (inrange(y, y_min, y_max)) {
  1435.           *lx++ = x_min;
  1436.           *ly++ = y;
  1437.           intersect = TRUE;
  1438.        }
  1439.     }
  1440.  
  1441.     /* does it intersect x_max edge */
  1442.     if (inrange(x_max, ax, bx)) {
  1443.        y = ay + (x_max-ax) * ((by-ay) / (bx-ax));
  1444.        if (inrange(y, y_min, y_max)) {
  1445.           *lx++ = x_max;
  1446.           *ly++ = y;
  1447.           intersect = TRUE;
  1448.        }
  1449.     }
  1450.  
  1451.     if (intersect)
  1452.      return(TRUE);
  1453.  
  1454.     /* It is possible for one or more of the [ab][xy] values to be -VERYLARGE.
  1455.     * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned
  1456.     * FALSE above.
  1457.     * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  1458.     * Otherwise we fall through all the tests above. 
  1459.     * Handle them carefully here. As yet we have no way for them to be +VERYLARGE.
  1460.     */
  1461.     if (ax == -VERYLARGE) {
  1462.        if (ay != -VERYLARGE
  1463.           && inrange(by, y_min, y_max) && inrange(x_max, ax, bx)) {
  1464.           *lx++ = x_min;
  1465.           *ly = by;
  1466.           *lx++ = x_max;
  1467.           *ly = by;
  1468.           intersect = TRUE;
  1469.        }
  1470.     } else if (bx == -VERYLARGE) {
  1471.        if (by != -VERYLARGE
  1472.           && inrange(ay, y_min, y_max) && inrange(x_max, ax, bx)) {
  1473.           *lx++ = x_min;
  1474.           *ly = ay;
  1475.           *lx++ = x_max;
  1476.           *ly = ay;
  1477.           intersect = TRUE;
  1478.        }
  1479.     } else if (ay == -VERYLARGE) {
  1480.        /* note we know ax != -VERYLARGE */
  1481.        if (inrange(bx, x_min, x_max) && inrange(y_max, ay, by)) {
  1482.           *lx++ = bx;
  1483.           *ly = y_min;
  1484.           *lx++ = bx;
  1485.           *ly = y_max;
  1486.           intersect = TRUE;
  1487.        }
  1488.     } else if (by == -VERYLARGE) {
  1489.        /* note we know bx != -VERYLARGE */
  1490.        if (inrange(ax, x_min, x_max) && inrange(y_max, ay, by)) {
  1491.           *lx++ = ax;
  1492.           *ly = y_min;
  1493.           *lx++ = ax;
  1494.           *ly = y_max;
  1495.           intersect = TRUE;
  1496.        }
  1497.     }
  1498.  
  1499.     return(intersect);
  1500. }
  1501.  
  1502. /* Polar transform of all curves */
  1503. /* Original code by John Campbell (CAMPBELL@NAUVAX.bitnet) */
  1504. polar_xform (plots, pcount)
  1505.     struct curve_points *plots;
  1506.     int pcount;            /* count of curves in plots array */
  1507. {
  1508.      struct curve_points *this_plot;
  1509.      int curve;            /* loop var, for curves */
  1510.      register int i, p_cnt;    /* loop/limit var, for points */
  1511.      struct coordinate GPHUGE *pnts;    /* abbrev. for points array */
  1512.     double x, y;            /* new cartesian value */
  1513.     TBOOLEAN anydefined = FALSE;
  1514.     double d2r;
  1515.  
  1516.     if(angles_format == ANGLES_DEGREES){
  1517.         d2r = DEG2RAD;
  1518.     } else {
  1519.         d2r = 1.0;
  1520.     }
  1521.  
  1522. /*
  1523.     Cycle through all the plots converting polar to rectangular.
  1524.      If autoscaling, adjust max and mins. Ignore previous values.
  1525.     If not autoscaling, use the yrange for both x and y ranges.
  1526. */
  1527.     if (autoscale_ly) {
  1528.         x_min = VERYLARGE;
  1529.         y_min = VERYLARGE;
  1530.         x_max = -VERYLARGE;
  1531.         y_max = -VERYLARGE;
  1532.         autoscale_lx = TRUE;
  1533.     } else {
  1534.         x_min = y_min;
  1535.         x_max = y_max;
  1536.     }
  1537.     
  1538.     this_plot = plots;
  1539.     for (curve = 0; curve < pcount; this_plot = this_plot->next_cp, curve++) {
  1540.         p_cnt = this_plot->p_count;
  1541.         pnts = &(this_plot->points[0]);
  1542.  
  1543.     /*    Convert to cartesian all points in this curve. */
  1544.         for (i = 0; i < p_cnt; i++) {
  1545.             if (pnts[i].type != UNDEFINED) {
  1546.                  anydefined = TRUE;
  1547.                  /* modify points to reset origin and from degrees */
  1548.                  pnts[i].y -= rmin;
  1549.                  pnts[i].x *= d2r;
  1550.                  /* convert to cartesian coordinates */
  1551.                 x = pnts[i].y*cos(pnts[i].x);
  1552.                 y = pnts[i].y*sin(pnts[i].x);
  1553.                 pnts[i].x = x;
  1554.                 pnts[i].y = y;
  1555.                 if (autoscale_ly) {
  1556.                     if (x_min > x) x_min = x;
  1557.                     if (x_max < x) x_max = x;
  1558.                     if (y_min > y) y_min = y;
  1559.                     if (y_max < y) y_max = y;
  1560.                     pnts[i].type = INRANGE;
  1561.                 } else if(inrange(x, x_min, x_max) && inrange(y, y_min, y_max))
  1562.                   pnts[i].type = INRANGE;
  1563.                 else
  1564.                   pnts[i].type = OUTRANGE;
  1565.             }
  1566.         }    
  1567.     }
  1568.  
  1569.     if (autoscale_lx && anydefined && fabs(x_max - x_min) < zero) {
  1570.         /* This happens at least for the plot of 1/cos(x) (vertical line). */
  1571.         fprintf(stderr, "Warning: empty x range [%g:%g], ", x_min,x_max);
  1572.         if (x_min == 0.0) {
  1573.            x_min = -1; 
  1574.            x_max = 1;
  1575.         } else {
  1576.            x_min *= 0.9;
  1577.            x_max *= 1.1;
  1578.         }
  1579.         fprintf(stderr, "adjusting to [%g:%g]\n", x_min,x_max);
  1580.     }
  1581.     if (autoscale_ly && anydefined && fabs(y_max - y_min) < zero) {
  1582.         /* This happens at least for the plot of 1/sin(x) (horiz. line). */
  1583.         fprintf(stderr, "Warning: empty y range [%g:%g], ", y_min, y_max);
  1584.         if (y_min == 0.0) {
  1585.            y_min = -1;
  1586.            y_max = 1;
  1587.         } else {
  1588.            y_min *= 0.9;
  1589.            y_max *= 1.1;
  1590.         }
  1591.         fprintf(stderr, "adjusting to [%g:%g]\n", y_min, y_max);
  1592.     }
  1593. }
  1594.  
  1595. /* DRAW_YTICS: draw a regular tic series, y axis */
  1596. draw_ytics(start, incr, end)
  1597.         double start, incr, end; /* tic series definition */
  1598.         /* assume start < end, incr > 0 */
  1599. {
  1600.     double ticplace;
  1601.     int ltic;            /* for mini log tics */
  1602.     double lticplace;    /* for mini log tics */
  1603.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1604.  
  1605.     if (end == VERYLARGE)            /* for user-def series */
  1606.         end = max(y_min,y_max);
  1607.  
  1608.     /* limit to right side of plot */
  1609.     end = min(end, max(y_min,y_max));
  1610.  
  1611.     /* to allow for rounding errors */
  1612.     ticmin = min(y_min,y_max) - SIGNIF*incr;
  1613.     ticmax = max(y_min,y_max) + SIGNIF*incr;
  1614.     end = end + SIGNIF*incr; 
  1615.  
  1616.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1617.         if ( inrange(ticplace,ticmin,ticmax) )
  1618.             ytick(ticplace, yformat, incr, 1.0);
  1619.         if (is_log_y && incr == 1.0) {
  1620.             /* add mini-ticks to log scale ticmarks */
  1621.             int lstart, linc;
  1622.             if ((end - start) >= 10)
  1623.             {
  1624.             lstart = 10; /* No little ticks */
  1625.             linc = 5;
  1626.             }
  1627.             else if((end - start) >= 5)
  1628.             {
  1629.             lstart = 2; /* 4 per decade */
  1630.             linc = 3;
  1631.             }
  1632.             else
  1633.             {
  1634.             lstart = 2; /* 9 per decade */
  1635.             linc = 1;
  1636.             }
  1637.             for (ltic = lstart; ltic < (int)base_log_y; ltic += linc) {
  1638.                 lticplace = ticplace+log((double)ltic)/log_base_log_y;
  1639.                 if ( inrange(lticplace,ticmin,ticmax) )
  1640.                     ytick(lticplace, "\0", incr, 0.5);
  1641.             }
  1642.         }
  1643.     }
  1644. }
  1645.  
  1646. /* DRAW_XTICS: draw a regular tic series, x axis */
  1647. draw_xtics(start, incr, end)
  1648.         double start, incr, end; /* tic series definition */
  1649.         /* assume start < end, incr > 0 */
  1650. {
  1651.     double ticplace;
  1652.     int ltic;            /* for mini log tics */
  1653.     double lticplace;    /* for mini log tics */
  1654.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1655.  
  1656.     if (end == VERYLARGE)            /* for user-def series */
  1657.         end = max(x_min,x_max);
  1658.  
  1659.     /* limit to right side of plot */
  1660.     end = min(end, max(x_min,x_max));
  1661.  
  1662.     /* to allow for rounding errors */
  1663.     ticmin = min(x_min,x_max) - SIGNIF*incr;
  1664.     ticmax = max(x_min,x_max) + SIGNIF*incr;
  1665.     end = end + SIGNIF*incr; 
  1666.  
  1667.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1668.         if ( inrange(ticplace,ticmin,ticmax) )
  1669.             if(!polar || ticplace == start || ticplace == end) 
  1670.                 xtick(ticplace, xformat, incr, 1.0);
  1671.         if (is_log_x && incr == 1.0) {
  1672.             /* add mini-ticks to log scale ticmarks */
  1673.             int lstart, linc;
  1674.             if ((end - start) >= 10)
  1675.             {
  1676.             lstart = 10; /* No little ticks */
  1677.             linc = 5;
  1678.             }
  1679.             else if((end - start) >= 5)
  1680.             {
  1681.             lstart = 2; /* 4 per decade */
  1682.             linc = 3;
  1683.             }
  1684.             else
  1685.             {
  1686.             lstart = 2; /* 9 per decade */
  1687.             linc = 1;
  1688.             }
  1689.             for (ltic = lstart; ltic < (int)base_log_x; ltic += linc) {
  1690.                 lticplace = ticplace+log((double)ltic)/log_base_log_x;
  1691.                 if ( inrange(lticplace,ticmin,ticmax) )
  1692.                     xtick(lticplace, "\0", incr, 0.5);
  1693.             }
  1694.         }
  1695.     }
  1696. }
  1697.  
  1698. /* DRAW_SERIES_YTICS: draw a user tic series, y axis */
  1699. draw_series_ytics(start, incr, end)
  1700.         double start, incr, end; /* tic series definition */
  1701.         /* assume start < end, incr > 0 */
  1702. {
  1703.     double ticplace, place;
  1704.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1705.     double spacing = is_log_y ? log(incr)/log_base_log_y : incr;
  1706.  
  1707.     if (end == VERYLARGE)
  1708.         end = max(CheckLog(is_log_y, base_log_y, y_min),
  1709.               CheckLog(is_log_y, base_log_y, y_max));
  1710.     else
  1711.       /* limit to right side of plot */
  1712.       end = min(end, max(CheckLog(is_log_y, base_log_y, y_min),
  1713.                  CheckLog(is_log_y, base_log_y, y_max)));
  1714.  
  1715.     /* to allow for rounding errors */
  1716.     ticmin = min(y_min,y_max) - SIGNIF*incr;
  1717.     ticmax = max(y_min,y_max) + SIGNIF*incr;
  1718.     end = end + SIGNIF*incr; 
  1719.  
  1720.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1721.         place = (is_log_y ? log(ticplace)/log_base_log_y : ticplace);
  1722.         if ( inrange(place,ticmin,ticmax) )
  1723.          ytick(place, yformat, spacing, 1.0);
  1724.     }
  1725. }
  1726.  
  1727.  
  1728. /* DRAW_SERIES_XTICS: draw a user tic series, x axis */
  1729. draw_series_xtics(start, incr, end)
  1730.         double start, incr, end; /* tic series definition */
  1731.         /* assume start < end, incr > 0 */
  1732. {
  1733.     double ticplace, place;
  1734.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1735.     double spacing = is_log_x ? log(incr)/log_base_log_x : incr;
  1736.  
  1737.     if (end == VERYLARGE)
  1738.         end = max(CheckLog(is_log_x, base_log_x, x_min),
  1739.               CheckLog(is_log_x, base_log_x, x_max));
  1740.     else
  1741.       /* limit to right side of plot */
  1742.       end = min(end, max(CheckLog(is_log_x, base_log_x, x_min),
  1743.                  CheckLog(is_log_x, base_log_x, x_max)));
  1744.  
  1745.     /* to allow for rounding errors */
  1746.     ticmin = min(x_min,x_max) - SIGNIF*incr;
  1747.     ticmax = max(x_min,x_max) + SIGNIF*incr;
  1748.     end = end + SIGNIF*incr; 
  1749.  
  1750.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1751.         place = (is_log_x ? log(ticplace)/log_base_log_x : ticplace);
  1752.         if ( inrange(place,ticmin,ticmax) )
  1753.          xtick(place, xformat, spacing, 1.0);
  1754.     }
  1755. }
  1756. char *month[]={
  1757.     "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
  1758. };
  1759. draw_month_ytics()
  1760.     long l_tickplace,l_incr,l_end,m_calc;
  1761.  
  1762.     l_tickplace = (long)y_min;
  1763.     if((double)l_tickplace<y_min)l_tickplace++;
  1764.     l_end=(double)y_max;
  1765.     l_incr=(l_end-l_tickplace+1)/12;
  1766.     if(l_incr<1)l_incr=1;
  1767.     while(l_tickplace<=l_end)
  1768.     {
  1769.     m_calc = (l_tickplace-1)%12;
  1770.     if(m_calc<0)m_calc += 12;
  1771.     ytick((double)l_tickplace,month[m_calc],(double)l_incr,1.0);
  1772.     l_tickplace += l_incr;
  1773.     }
  1774. }
  1775. draw_month_xtics()
  1776. {
  1777.     long l_tickplace,l_incr,l_end,m_calc;
  1778.  
  1779.     l_tickplace = (long)x_min;
  1780.     if((double)l_tickplace<x_min)l_tickplace++;
  1781.     l_end=(double)x_max;
  1782.     l_incr=(l_end-l_tickplace+1)/12;
  1783.     if(l_incr<1)l_incr=1;
  1784.     while(l_tickplace<=l_end)
  1785.     {
  1786.     m_calc = (l_tickplace-1)%12;
  1787.     if(m_calc<0)m_calc += 12;
  1788.     xtick((double)l_tickplace,month[m_calc],(double)l_incr,1.0);
  1789.     l_tickplace += l_incr;
  1790.     }
  1791. }
  1792. char *day[]={
  1793.     "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
  1794. };
  1795. draw_day_ytics()
  1796.     long l_tickplace,l_incr,l_end,m_calc;
  1797.  
  1798.     l_tickplace = (long)y_min;
  1799.     if((double)l_tickplace<y_min)l_tickplace++;
  1800.     l_end=(double)y_max;
  1801.     l_incr=(l_end-l_tickplace+1)/14;
  1802.     if(l_incr<1)l_incr=1;
  1803.     while(l_tickplace<=l_end)
  1804.     {
  1805.     m_calc = l_tickplace%7;
  1806.     if(m_calc<0)m_calc += 7;
  1807.     ytick((double)l_tickplace,day[m_calc],(double)l_incr,1.0);
  1808.     l_tickplace += l_incr;
  1809.     }
  1810. }
  1811. draw_day_xtics()
  1812.     long l_tickplace,l_incr,l_end,m_calc;
  1813.  
  1814.     l_tickplace = (long)x_min;
  1815.     if((double)l_tickplace<x_min)l_tickplace++;
  1816.     l_end=(double)x_max;
  1817.     l_incr=(l_end-l_tickplace+1)/14;
  1818.     if(l_incr<1)l_incr=1;
  1819.     while(l_tickplace<=l_end)
  1820.     {
  1821.     m_calc = l_tickplace%7;
  1822.     if(m_calc<0)m_calc += 7;
  1823.     xtick((double)l_tickplace,day[m_calc],(double)l_incr,1.0);
  1824.     l_tickplace += l_incr;
  1825.     }
  1826. }
  1827. /* DRAW_SET_YTICS: draw a user tic set, y axis */
  1828. draw_set_ytics(list)
  1829.     struct ticmark *list;    /* list of tic marks */
  1830. {
  1831.     double ticplace;
  1832.     double incr = (y_max - y_min) / 10;
  1833.     /* global x_min, x_max, xscale, y_min, y_max, yscale */
  1834.  
  1835.     while (list != NULL) {
  1836.        ticplace = (is_log_y ? log(list->position)/log_base_log_y
  1837.                 : list->position);
  1838.        if ( inrange(ticplace, y_min, y_max)         /* in range */
  1839.           || NearlyEqual(ticplace, y_min, incr)    /* == y_min */
  1840.           || NearlyEqual(ticplace, y_max, incr))    /* == y_max */
  1841.         ytick(ticplace, list->label, incr, 1.0);
  1842.  
  1843.        list = list->next;
  1844.     }
  1845. }
  1846.  
  1847. /* DRAW_SET_XTICS: draw a user tic set, x axis */
  1848. draw_set_xtics(list)
  1849.     struct ticmark *list;    /* list of tic marks */
  1850. {
  1851.     double ticplace;
  1852.     double incr = (x_max - x_min) / 10;
  1853.     /* global x_min, x_max, xscale, y_min, y_max, yscale */
  1854.  
  1855.     while (list != NULL) {
  1856.        ticplace = (is_log_x ? log(list->position)/log_base_log_x
  1857.                 : list->position);
  1858.        if ( inrange(ticplace, x_min, x_max)         /* in range */
  1859.           || NearlyEqual(ticplace, x_min, incr)    /* == x_min */
  1860.           || NearlyEqual(ticplace, x_max, incr))    /* == x_max */
  1861.         xtick(ticplace, list->label, incr, 1.0);
  1862.  
  1863.        list = list->next;
  1864.     }
  1865. }
  1866.  
  1867. /* draw and label a y-axis ticmark */
  1868. ytick(place, text, spacing, ticscale)
  1869.         double place;                   /* where on axis to put it */
  1870.         char *text;                     /* optional text label */
  1871.         double spacing;         /* something to use with checkzero */
  1872.         double ticscale;         /* scale factor for tic mark (0..1] */
  1873. {
  1874.     register struct termentry *t = &term_tbl[term];
  1875.     char ticlabel[101];
  1876.     int ticsize = (int)((t->h_tic) * ticscale);
  1877.  
  1878.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1879.     if (grid) {
  1880.            (*t->linetype)(-1);  /* axis line type */
  1881.            /* do not put a rectangular grid on a polar plot */
  1882.        if( !polar){
  1883.          (*t->move)(xleft, map_y(place));
  1884.          (*t->vector)(xright, map_y(place));
  1885.            } else {   /* put a circular grid for polar -- not clipped! */
  1886.              int i;
  1887.         (*t->move)(map_x(ZERO), map_y(place));
  1888.         for( i=0; i <= 360; i++)
  1889.            (*t->vector)( map_x(place*sin( (double) DEG2RAD*i)),
  1890.             map_y(place*cos( (double) DEG2RAD*i)) );
  1891.         }
  1892.        (*t->linetype)(-2); /* border linetype */
  1893.     }
  1894.     if (tic_in) {
  1895.       /* if polar plot, put the tics along the axes */
  1896.       if( polar){
  1897.            (*t->move)(map_x(ZERO),map_y(place));
  1898.            (*t->vector)(map_x(ZERO) + ticsize, map_y(place));
  1899.            (*t->move)(map_x(ZERO), map_y(place));
  1900.            (*t->vector)(map_x(ZERO) - ticsize, map_y(place));
  1901.      } else {
  1902.        (*t->move)(xleft, map_y(place));
  1903.            (*t->vector)(xleft + ticsize, map_y(place));
  1904.            (*t->move)(xright, map_y(place));
  1905.            (*t->vector)(xright - ticsize, map_y(place));
  1906.      }
  1907.     } else {
  1908.       if( polar){
  1909.            (*t->move)(map_x(ZERO), map_y(place));
  1910.            (*t->vector)(map_x(ZERO) - ticsize, map_y(place));
  1911.      }else{
  1912.            (*t->move)(xleft, map_y(place));
  1913.            (*t->vector)(xleft - ticsize, map_y(place));
  1914.      }
  1915.     }
  1916.  
  1917.     /* label the ticmark */
  1918.     if (text == NULL) 
  1919.      text = yformat;
  1920.     
  1921.     if( polar){
  1922.       (void) sprintf(ticlabel, text,
  1923.         CheckLog(is_log_y, base_log_y, fabs( place)+rmin));
  1924.       if ((*t->justify_text)(RIGHT)) {
  1925.        (*t->put_text)(map_x(ZERO)-(t->h_char),
  1926.                    map_y(place), ticlabel);
  1927.      } else {
  1928.        (*t->put_text)(map_x(ZERO)-(t->h_char)*(strlen(ticlabel)+1),
  1929.                    map_y(place), ticlabel);
  1930.      }
  1931.     } else {
  1932.     
  1933.       (void) sprintf(ticlabel, text, CheckLog(is_log_y, base_log_y, place));
  1934.       if ((*t->justify_text)(RIGHT)) {
  1935.        (*t->put_text)(xleft-(t->h_char),
  1936.                    map_y(place), ticlabel);
  1937.      } else {
  1938.        (*t->put_text)(xleft-(t->h_char)*(strlen(ticlabel)+1),
  1939.                    map_y(place), ticlabel);
  1940.      }
  1941.     }
  1942. }
  1943.  
  1944. /* draw and label an x-axis ticmark */
  1945. xtick(place, text, spacing, ticscale)
  1946.         double place;                   /* where on axis to put it */
  1947.         char *text;                     /* optional text label */
  1948.         double spacing;         /* something to use with checkzero */
  1949.         double ticscale;         /* scale factor for tic mark (0..1] */
  1950. {
  1951.     register struct termentry *t = &term_tbl[term];
  1952.     char ticlabel[101];
  1953.     int ticsize = (int)((t->v_tic) * ticscale);
  1954.  
  1955.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1956.     if (grid) {
  1957.            (*t->linetype)(-1);  /* axis line type */
  1958.            if( !polar){  /* do not place a rectangular grid */
  1959.          (*t->move)(map_x(place), ybot);
  1960.          (*t->vector)(map_x(place), ytop);
  1961.            } else { /* angular lines only for start and stop */
  1962.          int i;
  1963.          for( i=0; i < 360; i+=10){
  1964.          (*t->move)(map_x(ZERO),map_y(ZERO) );
  1965.          (*t->vector)(map_x(-place*cos((double) DEG2RAD*i)),
  1966.              map_y(-place*sin( (double)DEG2RAD*i)));
  1967.          if( i%90 == 0){
  1968.              (void) sprintf(ticlabel, "%d", i);
  1969.          (*t->put_text)(map_x(-1.05*place*cos((double) DEG2RAD*i))
  1970.              +(t->h_char)*strlen(ticlabel)/2,
  1971.              map_y(-1.05*place*sin( (double)DEG2RAD*i))
  1972.                  , ticlabel);
  1973.          }
  1974.          }
  1975.            }
  1976.        (*t->linetype)(-2); /* border linetype */
  1977.     }
  1978.     if (tic_in) {
  1979.       if( polar){
  1980.            (*t->move)(map_x(place), map_y(ZERO));
  1981.            (*t->vector)(map_x(place), map_y(ZERO) + ticsize);
  1982.            (*t->move)(map_x(place), map_y(ZERO));
  1983.            (*t->vector)(map_x(place), map_y(ZERO) - ticsize);
  1984.      } else{
  1985.            (*t->move)(map_x(place), ybot);
  1986.            (*t->vector)(map_x(place), ybot + ticsize);
  1987.            (*t->move)(map_x(place), ytop);
  1988.            (*t->vector)(map_x(place), ytop - ticsize);
  1989.      }
  1990.     } else {
  1991.       if( polar){
  1992.            (*t->move)(map_x(place), map_y(ZERO));
  1993.            (*t->vector)(map_x(place), map_y(ZERO) - ticsize);
  1994.      }else{
  1995.            (*t->move)(map_x(place), ybot);
  1996.            (*t->vector)(map_x(place), ybot - ticsize);
  1997.      }
  1998.     }
  1999.     
  2000.     /* label the ticmark */
  2001.     if (text == NULL)
  2002.      text = xformat;
  2003.  
  2004.     if(polar){
  2005.       (void) sprintf(ticlabel, text, CheckLog(is_log_x, base_log_x, fabs(place)+rmin));
  2006.       if ((*t->justify_text)(CENTRE)) {
  2007.        (*t->put_text)(map_x(place),
  2008.                    map_y(ZERO)-(t->v_char), ticlabel);
  2009.      } else {
  2010.        (*t->put_text)(map_x(place)-(t->h_char)*strlen(ticlabel)/2,
  2011.                    map_y(ZERO)-(t->v_char), ticlabel);
  2012.      }
  2013.     }else{
  2014.  
  2015.       (void) sprintf(ticlabel, text, CheckLog(is_log_x, base_log_x, place));
  2016.       if ((*t->justify_text)(CENTRE)) {
  2017.        (*t->put_text)(map_x(place),
  2018.                    ybot-(t->v_char), ticlabel);
  2019.      } else {
  2020.        (*t->put_text)(map_x(place)-(t->h_char)*strlen(ticlabel)/2,
  2021.                    ybot-(t->v_char), ticlabel);
  2022.      }
  2023.     }
  2024. }
  2025.